package com.ld.shieldsb.qrcode.service;

import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.io.OutputStream;
import java.net.CookieHandler;
import java.net.CookieManager;
import java.net.CookiePolicy;
import java.net.URL;
import java.util.Hashtable;

import javax.imageio.ImageIO;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.google.zxing.BinaryBitmap;
import com.google.zxing.DecodeHintType;
import com.google.zxing.Result;
import com.google.zxing.common.BitMatrix;
import com.google.zxing.common.GlobalHistogramBinarizer;
import com.google.zxing.qrcode.QRCodeReader;
import com.ld.shieldsb.common.core.util.StringUtils;
import com.ld.shieldsb.qrcode.reader.BufferedImageLuminanceSource;

public abstract class QRCodeService {
    public static final String CHARSET = "utf-8";
    public static final String FORMAT_NAME = "JPG";

    public Logger log = LoggerFactory.getLogger(QRCodeService.class);

    /**
     * 创建BufferedImage
     * 
     * @Title createImage
     * @author 吕凯
     * @date 2019年10月24日 下午3:08:03
     * @param content
     * @param logoImagePath
     * @param needCompress
     * @return
     * @throws Exception
     *             BufferedImage
     */
    public abstract BufferedImage createImage(String content, String logoImagePath, int width, int logowidth) throws Exception;

    /**
     * 绘制BufferedImage，比较是否符合传入的大小，如果不符合会缩放
     * 
     * @Title toBufferedImage
     * @author 吕凯
     * @date 2019年10月24日 下午4:57:34
     * @param matrix
     * @param width
     * @param height
     * @return
     * @throws IOException
     *             BufferedImage
     */
    public BufferedImage toBufferedImage(BitMatrix matrix, int width, int height) throws IOException {
        int qrCodeWidth = matrix.getWidth();
        int qrCodeHeight = matrix.getHeight();
        BufferedImage qrCode = new BufferedImage(qrCodeWidth, qrCodeHeight, BufferedImage.TYPE_INT_RGB);

        for (int x = 0; x < qrCodeWidth; x++) {
            for (int y = 0; y < qrCodeHeight; y++) {
                qrCode.setRGB(x, y, matrix.get(x, y) ? 0xFF000000 : 0xFFFFFFFF);
            }
        }

        // 若二维码的实际宽高和预期的宽高不一致, 则缩放
        if (qrCodeWidth != width || qrCodeHeight != height) {
            BufferedImage tmp = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
            tmp.getGraphics().drawImage(qrCode.getScaledInstance(width, height, java.awt.Image.SCALE_SMOOTH), 0, 0, null);
            qrCode = tmp;
        }

        return qrCode;
    }

    /**
     * 生成二维码
     * 
     * @Title encode
     * @author 吕凯
     * @date 2019年10月24日 下午3:02:23
     * @param content
     *            内容
     * @param imgPath
     *            中间图片可为空
     * @param destPath
     *            输出路径
     * @param needCompress
     *            是否需要压缩
     * @throws Exception
     *             void
     */
    public abstract void encode(String content, String logoImagePath, int width, int logowidth, String destImagePath) throws Exception;

    public void encode(String content, int width, String destImagePath) throws Exception {
        encode(content, null, width, -1, destImagePath);
    };

    /**
     * 输出到流
     * 
     * @Title encode
     * @author 吕凯
     * @date 2019年10月24日 下午5:33:02
     * @param content
     * @param imgPath
     * @param width
     * @param logowidth
     * @param output
     * @param needCompress
     * @throws Exception
     *             void
     */
    public void encode(String content, String logoImagePath, int width, int logoWidth, OutputStream output) throws Exception {
        BufferedImage image = createImage(content, logoImagePath, width, logoWidth);
        ImageIO.write(image, FORMAT_NAME, output);
    };

    public void encode(String content, int width, OutputStream output) throws Exception {
        encode(content, null, width, -1, output);
    };

    /**
     * 生成二维码，返回BufferedImage
     * 
     * @Title encode
     * @author 吕凯
     * @date 2019年10月24日 下午3:04:41
     * @param content
     * @param logoImagePath
     * @param needCompress
     * @return
     * @throws Exception
     *             BufferedImage
     */
    public abstract BufferedImage encode(String content, String logoImagePath, int width, int logowidth) throws Exception;

    public BufferedImage encode(String content, int width) throws Exception {
        return encode(content, null, width, -1);
    }

    /**
     * 解码二维码
     * 
     * @Title decode
     * @author 吕凯
     * @date 2019年10月24日 下午3:01:49
     * @param file
     * @return
     * @throws Exception
     *             String
     */
    public String decode(File file) throws Exception {
        BufferedImage image;
        image = ImageIO.read(file);
        if (image == null) {
            return null;
        }
        return decode(image);
    }

    public String decode(BufferedImage image) throws Exception {
        BufferedImageLuminanceSource source = new BufferedImageLuminanceSource(image);
        // 将图片转换成二进制图片
        BinaryBitmap bitmap = new BinaryBitmap(new GlobalHistogramBinarizer(source));
        Result result;

        Hashtable<DecodeHintType, String> hints = new Hashtable<>();
        hints.put(DecodeHintType.CHARACTER_SET, CHARSET);
        result = new QRCodeReader().decode(bitmap, hints);
        String resultStr = result.getText();
        return resultStr;
    }

    /**
     * 解码二维码
     * 
     * @Title decode
     * @author 吕凯
     * @date 2019年10月24日 下午3:01:25
     * @param path
     *            二维码本地路径
     * @return
     * @throws Exception
     *             String
     */
    public String decode(String path) throws Exception {
        BufferedImage logImage = null;
        if (path.startsWith("http:") || path.startsWith("https:")) { // 网络图片
            URL url = new URL(path);
            logImage = ImageIO.read(url.openStream());
        } else { // 本地图片
            File file = new File(path);
            if (!file.exists()) {
                System.err.println("" + path + "   该文件不存在！");
                return null;
            }
            logImage = ImageIO.read(new File(path));
        }
        return decode(logImage);
    }

    public void mkdirs(String destPath) {
        File file = new File(destPath);
        // 当文件夹不存在时，mkdirs会自动创建多层目录，区别于mkdir．(mkdir如果父目录不存在则会抛出异常)
        if (!file.exists() && !file.isDirectory()) {
            file.mkdirs();
        }
    }

    /**
     * 插入logo图片，一般在中间
     * 
     * @Title overlapImage
     * @author 吕凯
     * @date 2019年10月24日 下午3:08:31
     * @param image
     * @param logoImagePath
     * @param logoImagePath
     * @throws Exception
     *             void
     */
    public void overlapImage(BufferedImage image, String logoImagePath, int width) throws IOException {
        if (image != null && StringUtils.isNotEmpty(logoImagePath) && width > 0) {
            // 插入中间图片
            BufferedImage logImage = null;

            if (logoImagePath.startsWith("http:") || logoImagePath.startsWith("https:")) { // 网络图片
                URL url = new URL(logoImagePath);
                logImage = ImageIO.read(url.openStream());
            } else { // 本地图片
                File file = new File(logoImagePath);
                if (!file.exists()) {
                    System.err.println("" + logoImagePath + "   该文件不存在！");
                    return;
                }
                logImage = ImageIO.read(new File(logoImagePath));
            }

            int logoImgWidth = logImage.getWidth(); // 设置logo图片长宽一致
            int logoImgHeight = logImage.getHeight(); //
            int logoWidth = width; // 设置logo图片长宽一致
            int logoHeight = logoImgHeight * logoWidth / logoImgWidth; //
            int logoX = (image.getWidth() - logoWidth) / 2; // 设置logo图片的位置,这里令其居中
            int logoY = (image.getHeight() - logoHeight) / 2; // 设置logo图片的位置,这里令其居中
            Graphics2D graphics = image.createGraphics();
            CookieHandler.setDefault(new CookieManager(null, CookiePolicy.ACCEPT_ALL));
            graphics.drawImage(logImage.getScaledInstance(logoWidth, logoHeight, BufferedImage.SCALE_SMOOTH), logoX, logoY, null);
        }

    }

}
